home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-03-31 | 26.8 KB | 876 lines | [TEXT/MPS ] |
- {------------------------------------------------------------------------------
- #
- # Apple Macintosh Developer Technical Support
- #
- # "Skippy White's Famous High Level Off-Screen Map Routines”
- #
- # Offscreen.inc1.p - Pascal Source
- #
- # Copyright © 1989 Apple Computer, Inc.
- # All rights reserved.
- # The characters depicted herein (except Skippy White) are fictitious.
- #
- # Versions:
- # 1.00 04/89
- #
- # Components:
- # Offscreen.p April 1, 1988
- # Offscreen.inc1.p April 1, 1988
- #
- # These routines provide a high-level interface to the QuickDraw & Color
- # Manager routines which allow the creation and manipulation of off-screen
- # bitmaps and pixmaps. They are designed to run on any machine with 128K or
- # later ROMs (sorry 64K ROM fans).
- # Note that the design incorporates the idea that you can go along pretending
- # there is an offscreen buffer even when one couldn’t be allocated, and the
- # calls will do nothing.
- #
- ------------------------------------------------------------------------------}
-
- CONST
- noDepth = -2;
- chunky = 0;
-
- TYPE
- PrivateHandle = ^PrivatePtr;
- PrivatePtr = ^PrivateRecord;
- PrivateRecord = RECORD
- requestedBounds : Rect; {boundary rectangle for the pixmap}
- {used to determine the depth, size, and dimensions of the pixmap}
-
- requestedDepth : INTEGER; {the requested depth of this map}
- {if > 0, a private device will be created for the map}
-
- requestedColors : CTabHandle; {color table}
- {our own copy of the color table that was passed in}
-
- requestedPolite : BOOLEAN; {whether he wanted it polite}
-
- bits : Handle; {handle to the off-screen bits}
- {if NIL, there is no port or graphics device either}
- notOurs : BOOLEAN; {TRUE means that we didn’t create the bits}
- needs32Bits : BOOLEAN; {you must be in 32 bit memory mode to get to bits}
-
- bitsPort : CGrafPtr; {GrafPort used for the off-screen map.}
- bitsDevice : GDHandle; {GDevice associated with the map}
- {private device (if requestedDepth > 0)}
- {(from the device list for requestedDepth = kMaxDepth)}
-
- oldSeed : LONGINT; {old CTSeed for the pixmap's color table}
- {used to detect color updates}
-
- invalRegion : RgnHandle; {part of offscreen buffer that is invalid}
-
- drawingPort : GrafPtr; {supplied to BeginOffscreenDahling}
- savedPort : GrafPtr; {saves old GrafPort while drawing off screen}
- savedMap : BitMap; {used to save map when we don’t use our port}
- savedVisRgn : RgnHandle; {saves the visRgn from a user-supplied port}
- savedDevice : GDHandle; {saves old GDevice while drawing off screen}
- END; {PrivateRecord}
-
-
-
- VAR
- theMac : SysEnvRec;
-
-
- {---------- low-level service routines used by the rest of Offscreen ----------}
-
- {Fill out the pixmap according to the bounds, pixelType, pixelSize, cmpCount,
- cmpSize and pmTable parameters. All fields will be modified.
- The initial pixmap will be copied from the current GDevice’s pixmap, so you must modify
- the pmap^^.baseAddr before using it.
- dataSize will return with the number of bytes required for the pixel data.
- Note: it is the responsibility of the caller to fill in the baseAddr field
- of the pixmap. You may want to call NewImprovedGBuffer to see if the system will
- allocate the data space and then set baseAddr to point to it.
- This call cannot fail.}
- PROCEDURE InitGBufferPixmap(pmap: PixMapHandle; aBounds: Rect; aPixelType, aPixelSize,
- aCmpCount, aCmpSize: INTEGER; aPMTable: CTabHandle; VAR dataSize: LONGINT);
-
- VAR
- theGDevice: GDHandle;
- BEGIN
- theGDevice := GetGDevice; {get the current device}
- pmap^^:=theGDevice^^.gdPMap^^; {start out with device’s pixmap}
- WITH pmap^^ DO BEGIN
- bounds := aBounds;
- pixelType := aPixelType;
- pixelSize := aPixelSize;
- cmpCount := aCmpCount;
- cmpSize := aCmpSize;
- pmTable := aPMTable;
- WITH bounds DO BEGIN
- rowBytes := ((pixelSize * right + 15) DIV 16) * 2;
- {calculate an even # of words}
- dataSize := bottom * LONGINT(rowBytes); {calculate the size}
- rowBytes := rowBytes + $8000; {flag that it’s a pixmap}
- END; {WITH}
- END; {WITH}
- END; {InitGBufferPixmap}
-
- {Fill out a pixmap for use with an onscreen grafPort. It differs from InitGBufferPixmap
- in that it associates the buffer with an onscreen device. This will be the maximim-
- depth device which intersects the globalBounds rectangle. In the most common case
- you will pass in the portRect of a window after converting it to global coordinates.
- If no screen device intersects globalBounds, the function will return FALSE and
- device will return with NIL. If it returns TRUE then device will be a handle to
- the proper GDevice (see StartLeech, below).
- For the other information, see the comments at InitGBufferPixmap.}
- FUNCTION InitGBufferScreen(pmap: PixMapHandle; globalBounds: Rect; VAR device:GDHandle;
- VAR dataSize: LONGINT): BOOLEAN;
-
- VAR
- savedDevice: GDHandle;
- BEGIN
- InitGBufferScreen := FALSE;
-
- device := GetMaxDevice(globalBounds); {maximum-depth device for globalBounds}
- IF device <> NIL THEN BEGIN
- savedDevice := GetGDevice;
-
- WITH globalBounds DO
- SetRect(globalBounds, 0, 0, right - left, bottom - top);
- {make globalBounds into a window-ish (zero-based) rectangle}
-
- SetGDevice(device); {set to device for InitGBufferPixmap}
- WITH device^^.gdPMap^^ DO
- InitGBufferPixmap(pmap, globalBounds, pixelType, pixelSize,
- cmpCount, cmpSize, pmTable, dataSize);
- {set up the pixmap}
-
- SetGDevice(savedDevice);
- InitGBufferScreen := TRUE;
- END; {IF device <> NIL}
- END; {InitGBufferScreen}
-
- {Allocate the data space for the bits of an offscreen buffer. Only do so if
- it can be allocated in an optimum place for graphics use. If the system
- doesn’t have a superior place to allocate the bits, NIL is returned.
- needs32Bits will return TRUE if the bit space requires 32 bit addressing
- in order to access it. buffNotNeeded will return TRUE if performance will be
- improved by NOT buffering (“performance” means avoiding flicker, etc.)}
- FUNCTION NewImprovedGBuffer(dataSize: LONGINT; VAR needs32Bits: BOOLEAN;
- VAR buffNotNeeded: BOOLEAN): Ptr;
-
- BEGIN
- NewImprovedGBuffer := NIL;
- needs32Bits := FALSE;
- buffNotNeeded := FALSE;
- END; {NewImprovedGBuffer}
-
- {Free a buffer allocated via NewImprovedGBuffer.}
- PROCEDURE FreeEnhancedGBuffer(bits: Ptr);
-
- BEGIN
- END; {FreeEnhancedGBuffer}
-
- {Fill out the GDevice record and set device^^.gdPMap = pixmap. Errors can occur from not
- being able to build the ITable, etc.}
- FUNCTION InitGBufferDevice(device: GDHandle; pmap: PixMapHandle): OSErr;
-
- VAR
- preferredResolution: INTEGER;
- inverseTable: ITabHandle;
-
- PROCEDURE Out(error: OSErr);
- BEGIN {Out}
- IF error <> noErr THEN BEGIN
- DisposHandle(Handle(device^^.gdITable)); {get rid of the inverse table}
- InitGBufferDevice := error;
- EXIT(InitGBufferDevice);
- END; {IF error <> noErr}
- END; {Out}
-
- BEGIN
- device^^.gdITable := NIL;
- inverseTable := ITabHandle(NewHandle(0)); {create the inverse table stub}
- Out(MemError); {bail if couldn’t make the handle}
- MakeITable(pmap^^.pmTable, inverseTable, preferredResolution);
- Out(QDError); {bail if MakeITable failed}
-
- preferredResolution := GetMainDevice^^.gdResPref; {preferred resolution ??? is this cool?}
-
- WITH device^^ DO BEGIN
- gdType := clutType; {no private devices for direct ones, right?}
- gdITable := inverseTable;
- gdResPref := preferredResolution;
- gdFlags := 2 ** noDriver;
- gdPMap := pmap;
- gdRect := pmap^^.bounds;
- END; {WITH}
-
- InitGBufferDevice := noErr;
- END; {InitGBufferDevice}
-
-
- {---------- end of low-level service routines ----------}
-
-
- PROCEDURE InitOffscreen;
- {128K ROMs and new enough Palette Manager}
-
- VAR
- error : OSErr;
-
- BEGIN {InitOffscreen}
- error := SysEnvirons(1, theMac);
- END; {InitOffscreen}
-
-
- (* ??? commented out since we no longer use it (but someone may want it, so should we provide it as a utility?)
- FUNCTION GetMaxAreaDevice(globalRect: Rect): GDHandle;
- {Find the greatest overlap device for the given global rectangle.}
-
- VAR
- area : LONGINT;
- maxArea : LONGINT;
- device : GDHandle;
- intersection : Rect;
-
- BEGIN {GetMaxAreaDevice}
- GetMaxAreaDevice := NIL;
-
- maxArea := 0;
-
- device := GetDeviceList;
- WHILE device <> NIL DO BEGIN
- IF TestDeviceAttribute(device, screenDevice) THEN
- IF TestDeviceAttribute(device, screenActive) THEN
- IF SectRect(globalRect, device^^.gdRect, intersection) THEN BEGIN
- WITH intersection DO
- area := LONGINT(right - left) * LONGINT(bottom - top);
- IF area > maxArea THEN BEGIN
- GetMaxAreaDevice := device;
- maxArea := area;
- END; {IF area > maxArea}
- END; {IF SectRect...}
- device := GetNextDevice(device);
- END; {WHILE device <> NIL}
- END; {GetMaxAreaDevice}
- *)
-
-
-
- FUNCTION MakeCleanColorTable(colors: CTabHandle; depth: INTEGER;
- VAR table: CTabHandle): OSErr;
- {This call takes a handle to a list of colors to be included in a color table.
- It returns a table suitable for use for a PixMap, with black and white at the
- correct offsets. If there is no default color table for the depth in question,
- it returns NIL for the table.}
-
- FUNCTION IsWhite(rgb: RGBColor): BOOLEAN;
- BEGIN {IsWhite}
- IsWhite := (rgb.red = $FFFF) & (rgb.green = $FFFF) & (rgb.blue = $FFFF);
- END; {IsWhite}
-
- FUNCTION IsBlack(rgb: RGBColor): BOOLEAN;
- BEGIN {IsBlack}
- IsBlack := (rgb.red = 0) & (rgb.green = 0) & (rgb.blue = 0);
- END; {IsBlack}
-
- VAR
- tableIndex : INTEGER;
- colorIndex : INTEGER;
- aColor : RGBColor;
-
- BEGIN {MakeCleanColorTable}
- table := GetCTable(depth);
- IF table = NIL THEN
- MakeCleanColorTable := memFullErr
- ELSE
- WITH table^^ DO BEGIN
- ctSeed := GetCTSeed; {get a fresh seed; we'll change the color table}
-
- tableIndex := 1; {skip white in table we are making}
- colorIndex := 0; {start with first color}
-
- REPEAT
- IF colorIndex > colors^^.ctSize THEN
- Leave; {done with all the colors}
- aColor := colors^^.ctTable[colorIndex].rgb;
- colorIndex := colorIndex + 1; {advance to next color}
- IF IsWhite(aColor) THEN
- Cycle; {this one is white, try another}
- IF IsBlack(aColor) THEN
- Cycle; {this one is black, try another}
-
- {$PUSH} {$R-}
- ctTable[tableIndex].rgb := aColor; {use this color}
- {$POP}
- tableIndex := tableIndex + 1;
- UNTIL tableIndex > ctSize - 1; {until the table is full}
-
- MakeCleanColorTable := noErr;
- END; {WITH}
- END; {MakeCleanColorTable}
-
-
-
- PROCEDURE DeallocateBits(offscreenHandle: Handle);
- {Get rid of the bits from an off-screen map.}
-
- BEGIN {DeallocateBits}
- IF offscreenHandle <> NIL THEN
- WITH PrivateHandle(offscreenHandle)^^ DO BEGIN
- IF NOT notOurs THEN
- DisposHandle(bits) {get rid of the bits}
- ELSE
- FreeEnhancedGBuffer(Ptr(bits));
- bits := NIL;
-
- IF bitsPort <> NIL THEN BEGIN
- IF bitsPort^.visRgn <> NIL THEN BEGIN {visRgn of NIL means port is not open yet}
- IF requestedDepth > 0 THEN {if we created a private device and color table}
- DisposHandle(Handle(bitsPort^.portPixMap^^.pmTable)); {get rid of the colors}
- ClosePort(GrafPtr(bitsPort));
-
- DisposeRgn(invalRegion); {get rid of the invalidation region}
- END; {IF ...bitsPort^.visRgn <> NIL}
- DisposPtr(Ptr(bitsPort));
- END; {IF bitsPort <> NIL}
- bitsPort := NIL;
-
- IF bitsDevice <> NIL THEN
- IF requestedDepth > 0 THEN BEGIN {if we created a private device}
- bitsDevice^^.gdPMap := NIL; {the pixmap was owned by the port}
- DisposGDevice(bitsDevice);
- bitsDevice := NIL;
- END; {IF requestedDepth > 0}
- END; {WITH}
- END; {DeallocateBits}
-
-
-
- FUNCTION GetMap(offscreenHandle: Handle): BitMapPtr;
- {Get a BitMapPtr for the bits in the offscreen handle.
- This is also the best way to see if the bits are allocated.
- Note that this has a side-effect of setting up the baseAddr properly.}
-
- VAR
- map : BitMapPtr;
-
- BEGIN {GetMap}
- map := NIL;
-
- IF offscreenHandle <> NIL THEN {if we have bits}
- WITH PrivateHandle(offscreenHandle)^^ DO BEGIN
- IF bits <> NIL THEN {if we seem to have bits, make sure that we really do}
- IF StripAddress(bits^) = NIL THEN
- DeallocateBits(offscreenHandle)
- ELSE BEGIN
- {find the map}
- WITH bitsPort^ DO
- IF portVersion > 0 THEN {old-style port?}
- map := @portPixMap {this is really portBits!}
- ELSE
- map := BitMapPtr(portPixMap^);
- IF notOurs THEN
- map^.baseAddr := Ptr(bits)
- ELSE
- map^.baseAddr := bits^;
- END; {ELSE}
- END; {WITH}
- GetMap := map;
- END; {GetMap}
-
-
-
- FUNCTION GetBitsHandle(offscreenHandle: Handle): Handle;
- BEGIN
- GetBitsHandle := NIL;
- IF offscreenHandle <> NIL THEN
- WITH PrivateHandle(offscreenHandle)^^ DO
- IF NOT notOurs THEN
- GetBitsHandle := bits;
- END; {GetBitsHandle}
-
-
-
- FUNCTION AllocateBits(offscreenHandle: Handle; VAR buffNotNeeded: BOOLEAN): OSErr;
- {Allocate the bits, port, device, etc. for the off-screen map.
- If an error code is returned, the handle will be in the "dormant" stage. ??? define
- If the bits are already allocated, then nothing will happen.}
-
- VAR
- oldPort : GrafPtr;
- bounder : Rect;
- map : BitMapPtr;
- bitsSize : LONGINT;
- colors : CTabHandle;
- preferredResolution : INTEGER;
- inverseTable : ITabHandle;
- totalSpace : LONGINT;
- contiguousSpace : LONGINT;
- use32Bits : BOOLEAN;
-
- PROCEDURE Out(error: OSErr);
- BEGIN {Out}
- IF error <> noErr THEN BEGIN
- HUnlock(offscreenHandle);
- DeallocateBits(offscreenHandle);
- SetPort(oldPort);
- AllocateBits := error;
- EXIT(AllocateBits);
- END; {IF error <> noErr}
- END; {Out}
-
- BEGIN {AllocateBits}
- IF offscreenHandle <> NIL THEN
- IF GetMap(offscreenHandle) = NIL THEN BEGIN {if the bits are not already allocated}
- GetPort(oldPort);
-
- MoveHHi(offscreenHandle); {fly the handle high in the heap since we lock it down}
- HLock(offscreenHandle);
- WITH PrivateHandle(offscreenHandle)^^ DO BEGIN
- bitsPort := CGrafPtr(NewPtrClear(SIZEOF(GrafPort))); {create a new port}
- {NewPtrClear means that bits := NIL, invalRegion := NIL, notOurs := FALSE, etc.}
- Out(MemError);
-
- WITH requestedBounds DO
- SetRect(bounder, 0, 0, right - left, bottom - top);
-
- IF theMac.hasColorQD THEN
- WITH bitsPort^ DO BEGIN
- OpenCPort(bitsPort); {always use a color port}
- portPixMap^^.pmTable := NIL; {in case we fail before we make a color table}
-
- IF requestedDepth > 0 THEN BEGIN {if there is a private device}
- {make a color table from the requested colors or a resource file or ROM}
- Out(MakeCleanColorTable(requestedColors, requestedDepth, colors));
-
- {now set up the pixmap of the port}
- InitGBufferPixmap(portPixMap, bounder, chunky, requestedDepth, 1, requestedDepth,
- colors, {returns} bitsSize);
-
- {make a private device}
- bitsDevice := GDHandle(NewHandleClear(SIZEOF(GDevice)));
- Out(MemError); {must have failed because of heap paucity}
-
- inverseTable := ITabHandle(NewHandle(0)); {create the inverse table}
- Out(MemError);
- preferredResolution := GetMainDevice^^.gdResPref; {preferred resolution ??? is this cool?}
-
- WITH bitsDevice^^ DO BEGIN {set up the other fields of the device}
- gdType := clutType;
- gdITable := inverseTable;
- gdResPref := preferredResolution;
- gdFlags := 2 ** noDriver;
- gdPMap := portPixMap;
- END; {WITH}
- InitGDevice(0, -1, bitsDevice); {sets gdRect from pixmap now; in future may do more}
- MakeITable(colors, inverseTable, preferredResolution);
- Out(QDError); {MakeITable failed}
- END ELSE BEGIN {when there is no private device}
- {get the max. area device and set up the port’s pixmap accordingly}
- IF NOT InitGBufferScreen(portPixMap, requestedBounds, bitsDevice, {returns} bitsSize) THEN
- Out(noDeviceIntersectErr); {no devices intersect bounds}
-
- oldSeed := portPixMap^^.pmTable^^.ctSeed; {used to detect color updates}
- END;
-
- map := BitMapPtr(portPixMap^); {point to the map so we can set the portRect & visRgn}
-
- {!!! ??? Do we need to call ForeColor and BackColor on the CGrafPort to set it up right?}
-
- END {WITH}
- ELSE BEGIN {Classic QuickDraw}
- OpenPort(GrafPtr(bitsPort));
- WITH GrafPtr(bitsPort)^, portBits DO BEGIN
- bounds := bounder;
- {figure out how much space we need for our bits}
- WITH bounds DO BEGIN
- rowBytes := ((right + 15) DIV 16) * 2;
- {calculate an even # of words}
- bitsSize := bottom * LONGINT(rowBytes); {calculate the size}
- END; {WITH}
- map := @portBits; {point to the map so we can set it up}
- END; {WITH}
- END;
-
- WITH bitsPort^ DO BEGIN
- portRect := map^.bounds; {port's portRect is same as bounds}
- RectRgn(visRgn, portRect); {the visRgn must be changed}
- invalRegion := NewRgn;
- Out(MemError);
- CopyRgn(visRgn, invalRegion);
- END; {WITH}
-
- bits := Handle(NewImprovedGBuffer(bitsSize, needs32Bits, buffNotNeeded));
- notOurs := bits <> NIL;
- IF NOT notOurs THEN BEGIN
- IF requestedPolite THEN
- contiguousSpace := MaxBlock {make sure we have room without purging}
- ELSE
- PurgeSpace(totalSpace, contiguousSpace); {make sure we have room with purging}
- IF bitsSize + kOffscreenReserve > contiguousSpace THEN
- {if there is not enough room for the bits & reserve block, error out}
- Out(memFullErr);
- bits := NewHandleClear(bitsSize); {get space for the bits}
- Out(MemError);
- IF requestedPolite THEN
- HPurge(bits); {keep bits purgeable if we are polite}
- END;
-
- END; {WITH}
- HUnlock(offscreenHandle);
-
- SetPort(oldPort);
- END; {IF GetMap(offscreenHandle) = NIL}
-
- AllocateBits := noErr;
- END; {AllocateBits}
-
-
-
- PROCEDURE DisposeOffscreen(offscreenHandle: Handle);
- {Get rid of everything, including offscreenHandle itself.}
-
- BEGIN {DisposeOffscreen}
- IF offscreenHandle <> NIL THEN BEGIN
- DeallocateBits(offscreenHandle);
- DisposHandle(Handle(PrivateHandle(offscreenHandle)^^.requestedColors));
- DisposHandle(offscreenHandle);
- END; {IF offscreenHandle <> NIL}
- END; {DisposeOffscreen}
-
-
-
- FUNCTION NewOffscreen(bounds: Rect; depth: INTEGER; colors: CTabHandle;
- memoryPolite: BOOLEAN; VAR buffNotNeeded: BOOLEAN; VAR offscreenHandle: Handle): OSErr;
- {Create an offscreenHandle. Return NIL if there is an error.}
-
- VAR
- aHandle : Handle;
-
- PROCEDURE Out(error: OSErr);
- BEGIN {Out}
- IF error <> noErr THEN BEGIN
- DisposHandle(aHandle); {dispose handle if we made it}
- NewOffscreen := error;
- offscreenHandle := NIL;
- EXIT(NewOffscreen);
- END; {IF error <> noErr}
- END; {Out}
-
- BEGIN {NewOffscreen}
- aHandle := NewHandleClear(SizeOf(PrivateRecord)); {make the private block}
- Out(MemError);
-
- MoveHHi(aHandle); {fly this high so it doesn't fragment the heap}
- HLock(aHandle);
- WITH PrivateHandle(aHandle)^^ DO BEGIN
- requestedBounds := bounds;
- IF theMac.hasColorQD THEN
- requestedDepth := depth
- ELSE
- requestedDepth := noDepth;
- IF requestedDepth > 0 THEN BEGIN {if we need a private device}
- Out(HandToHand(Handle(colors)));
- requestedColors := colors;
- END;
- requestedPolite := memoryPolite;
- END; {WITH}
- HUnlock(aHandle);
-
- {now, we have filled in all of the fields of offscreenHandle}
- NewOffscreen := AllocateBits(aHandle, buffNotNeeded);
- offscreenHandle := aHandle;
- END; {NewOffscreen}
-
-
-
- FUNCTION CheckOffscreen(offscreenHandle: Handle; VAR drawNeeded: BOOLEAN): OSErr;
-
- VAR
- error : OSErr;
- newSeed : LONGINT;
- buffNotNeeded : BOOLEAN;
-
- BEGIN {CheckOffscreen}
- drawNeeded := TRUE; {default we must draw if offscreen invalid}
- error := noErr; {no error either}
- IF offscreenHandle <> NIL THEN
- WITH PrivateHandle(offscreenHandle)^^ DO BEGIN
- IF requestedDepth = kMaxDepth THEN {if it's not a private device}
- IF oldSeed <> bitsDevice^^.gdPMap^^.pmTable^^.ctSeed THEN {we have a color update, Houston}
- DeallocateBits(offscreenHandle);
-
- drawNeeded := GetMap(offscreenHandle) = NIL;
- error := AllocateBits(offscreenHandle, buffNotNeeded); {allocate if deallocated}
- END; {WITH}
-
- IF GetMap(offscreenHandle) <> NIL THEN
- drawNeeded := drawNeeded | (NOT EmptyRgn(PrivateHandle(offscreenHandle)^^.invalRegion));
- {can’t use the width for invalRegion since we may have done an AllocateBits}
-
- CheckOffscreen := error;
- END; {CheckOffscreen}
-
-
- PROCEDURE ValidRectOffscreen(offscreenHandle: Handle; window: WindowPtr; validRect: Rect);
-
- VAR
- validRgn : RgnHandle;
-
- BEGIN
- validRgn := NewRgn;
- RectRgn(validRgn, validRect);
- ValidRgnOffscreen(offscreenHandle, window, validRgn);
- DisposeRgn(validRgn);
- END; {ValidRectOffscreen}
-
-
- PROCEDURE ValidRgnOffscreen(offscreenHandle: Handle; window: WindowPtr; validRegion: RgnHandle);
-
- VAR
- savedPort : GrafPtr;
-
- BEGIN
- IF window <> NIL THEN BEGIN
- GetPort(savedPort);
- SetPort(window);
- ValidRgn(validRegion);
- SetPort(savedPort);
- END;
- IF GetMap(offscreenHandle) <> NIL THEN
- WITH PrivateHandle(offscreenHandle)^^ DO
- DiffRgn(invalRegion, validRegion, invalRegion);
- END; {ValidRgnOffscreen}
-
-
- PROCEDURE InvalRectOffscreen(offscreenHandle: Handle; window: WindowPtr; invalidRect: Rect);
-
- VAR
- invalidRgn : RgnHandle;
-
- BEGIN
- invalidRgn := NewRgn;
- RectRgn(invalidRgn, invalidRect);
- InvalRgnOffscreen(offscreenHandle, window, invalidRgn);
- DisposeRgn(invalidRgn);
- END; {InvalRectOffscreen}
-
-
- PROCEDURE InvalRgnOffscreen(offscreenHandle: Handle; window: WindowPtr; invalidRgn: RgnHandle);
-
- VAR
- savedPort : GrafPtr;
-
- BEGIN
- IF window <> NIL THEN BEGIN
- GetPort(savedPort);
- SetPort(window);
- InvalRgn(invalidRgn);
- SetPort(savedPort);
- END;
- IF GetMap(offscreenHandle) <> NIL THEN
- WITH PrivateHandle(offscreenHandle)^^ DO
- UnionRgn(invalRegion, invalidRgn, invalRegion);
- END; {ValidRgnOffscreen}
-
-
- FUNCTION CheckBoundsOffscreen(offscreenHandle: Handle; newBounds: Rect;
- VAR drawNeeded: BOOLEAN): OSErr;
-
- VAR
- somethingChanged : BOOLEAN;
- rightDevice : GDHandle;
-
- BEGIN {CheckBoundsOffscreen}
- IF offscreenHandle <> NIL THEN
- WITH PrivateHandle(offscreenHandle)^^ DO BEGIN
- {check to see if the size of the port changed}
- WITH newBounds, bitsPort^.portRect.botRight DO
- somethingChanged := (right - left <> h) | (bottom - top <> v);
-
- IF NOT somethingChanged THEN BEGIN
- {check to see if the depth of the screen changed}
- rightDevice := NIL;
- IF requestedDepth = kMaxDepth THEN
- rightDevice := GetMaxDevice(newBounds);
- somethingChanged := (rightDevice <> NIL) & (rightDevice <> bitsDevice);
- END;
-
- IF somethingChanged THEN BEGIN {we have a color update, Houston}
- DeallocateBits(offscreenHandle);
- requestedBounds := newBounds;
- END;
- END; {WITH}
- CheckBoundsOffscreen := CheckOffscreen(offscreenHandle, drawNeeded);
- END; {CheckBoundsOffscreen}
-
-
-
- PROCEDURE BeginOffscreenDrawing(offscreenHandle: Handle; port: GrafPtr);
- BEGIN {BeginOffscreenDrawing}
- IF GetMap(offscreenHandle) <> NIL THEN
- {note side effect here of setting up map for drawing (stuffing baseAddr)}
- WITH PrivateHandle(offscreenHandle)^^ DO BEGIN
- IF NOT notOurs THEN {if we, not the system, allocated the bits}
- {lock the bits down}
- HLock(bits);
-
- {we need the pixmap locked while we are using it}
- IF theMac.hasColorQD THEN
- HLock(Handle(bitsPort^.portPixMap));
-
- drawingPort := port;
- GetPort(savedPort);
-
- {set up the port and the device}
-
- IF drawingPort = NIL THEN
- SetPort(GrafPtr(bitsPort))
- ELSE BEGIN
- SetPort(drawingPort);
- {save the visRgn and replace it with our private one}
- savedVisRgn := drawingPort^.visRgn;
- drawingPort^.visRgn := bitsPort^.visRgn;
-
- savedMap := drawingPort^.portBits;
-
- IF theMac.hasColorQD THEN
- SetPortPix(bitsPort^.portPixMap)
- ELSE
- SetPortBits(GrafPtr(bitsPort)^.portBits);
- END; {for caller-supplied port case}
-
- IF theMac.hasColorQD THEN BEGIN
- savedDevice := GetGDevice;
- SetGDevice(bitsDevice);
- END; {IF theMac.hasColorQD}
-
- WITH thePort^ DO
- {intersect the invalidated offscreen region with private visRgn}
- SectRgn(invalRegion, visRgn, visRgn);
- END; {WITH}
- END; {BeginOffscreenDrawing}
-
-
-
- PROCEDURE EndOffscreenDrawing(offscreenHandle: Handle);
-
- TYPE
- PMapHandlePtr = ^PixMapHandle;
-
- BEGIN {EndOffscreenDrawing}
- IF GetMap(offscreenHandle) <> NIL THEN
- WITH PrivateHandle(offscreenHandle)^^ DO BEGIN
- {restore the map, device, port}
-
- IF drawingPort <> NIL THEN BEGIN
- SetPort(drawingPort);
- drawingPort^.visRgn := savedVisRgn; {restore original visRgn}
-
- IF theMac.hasColorQD THEN
- SetPortPix(PMapHandlePtr(@savedMap)^)
- ELSE
- SetPortBits(savedMap);
- END; {for caller-supplied port case}
-
- IF theMac.hasColorQD THEN
- SetGDevice(savedDevice);
-
- SetPort(savedPort);
-
- {we only need the pixmap locked while we are using it}
- IF theMac.hasColorQD THEN
- HUnlock(Handle(bitsPort^.portPixMap));
-
- IF NOT notOurs THEN
- {unlock the bits so they can float}
- HUnlock(bits);
-
- WITH bitsPort^ DO
- RectRgn(visRgn, portRect); {set private visRgn back to full size}
- END; {WITH}
- END; {EndOffscreenDrawing}
-
-
- PROCEDURE BeginUpdateOffscreen(offscreenHandle: Handle; window: WindowPtr);
- BEGIN
- BeginUpdate(window);
- IF GetMap(offscreenHandle) <> NIL THEN BEGIN
- BeginOffscreenDrawing(offscreenHandle, window); {’sects invalRegion with visRgn}
- {validate the entire contents of the offscreen buffer}
- ValidRectOffscreen(offscreenHandle, NIL, PrivateHandle(offscreenHandle)^^.bitsPort^.portRect);
- END;
- END; {BeginUpdateOffscreen}
-
-
- PROCEDURE EndUpdateOffscreen(offscreenHandle: Handle; window: WindowPtr);
- BEGIN
- IF GetMap(offscreenHandle) <> NIL THEN BEGIN
- EndOffscreenDrawing(offscreenHandle);
-
- SetPort(window);
- ForeColor(blackColor);
- BackColor(whiteColor);
- {now copy from the offscreen buffer to the window (clipped to window’s visRgn)}
- WITH PrivateHandle(offscreenHandle)^^ DO
- CopyBits(GrafPtr(bitsPort)^.portBits, window^.portBits, bitsPort^.portRect,
- window^.portRect, srcCopy, NIL);
- END;
- EndUpdate(window);
- END; {EndUpdateOffscreen}
-
-
- {Create an off-screen pixel map for a port.
- It will always use kMaxDepth and always be memoryPolite.}
-
- FUNCTION NewOffscreenForWindow(window: WindowPtr; VAR buffNotNeeded: BOOLEAN;
- VAR offscreenHandle: Handle): OSErr;
-
- VAR
- savedPort : GrafPtr;
- globalRect : Rect;
-
- BEGIN {NewOffscreenForWindow}
- SetPort(window);
-
- globalRect := window^.portRect; {calculate a global rect for this window}
- WITH globalRect DO BEGIN
- LocalToGlobal(topLeft);
- LocalToGlobal(botRight);
- END;
-
- NewOffscreenForWindow := NewOffscreen(globalRect, kMaxDepth, NIL, TRUE,
- buffNotNeeded, offscreenHandle);
- END; {NewOffscreenForWindow}
-
-
-
- (* ??? looks like these aren’t needed…
- {Begin an update for the window specified, using the specified off-screen
- handle for bits. This sets the port to the window! …and temporarily nukes
- the visRgn! ??? @@@ !!!}
-
- PROCEDURE BeginOffscreenUpdate(offscreenHandle: Handle; window: WindowPtr);
- BEGIN {BeginOffscreenUpdate}
- BeginOffscreenDrawing(offscreenHandle); {???!!!
- SetPort(window); {override the offscreen port which was set by BOU}
- BeginUpdate(window);
-
- END; {BeginOffscreenUpdate}
-
-
-
- {Finish drawing to an off-screen port. Also copy the bits from the
- port to the screen.}
-
- PROCEDURE EndOffscreenUpdate(offscreenHandle: Handle; window: WindowPtr);
-
-
-
- {Call this when the rectangle of the off-screen map needs to change, perhaps
- due to a window moving on the main screen. This will also check for any change
- in depth.}
-
- FUNCTION UpdateOffscreenForWindow(offscreenHandle: Handle; window: WindowPtr;
- VAR drawNeeded: BOOLEAN): OSErr;
- *)
-
-
- END. {Offscreen}
-